package com.booter.hessian.component;

import com.booter.hessian.annotation.HessianService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.remoting.caucho.HessianServiceExporter;
import org.springframework.util.ClassUtils;

/***
 * 将注解为HessianServerService的服务自动发布
 * 通过 继承 HessianServiceExporter 和 HessianProxyFactoryBean 可以实现授权认证 和基本的权限管理
 * 服务bean的默认名称为类名首字母小写
 *
 * @author lcw
 */
@Slf4j
public class HessianServerServiceExporterFactory implements ApplicationContextAware {


    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {

        try {
            //也可以使用ClassPathScanningCandidateComponentProvider扫包查找bean
//            new ClassPathScanningCandidateComponentProvider(false);

            ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context;

            //构建BeanFactory
            DefaultListableBeanFactory bf = (DefaultListableBeanFactory) cac.getAutowireCapableBeanFactory();

            //从spring 容器中过滤出带有HessianServerService注解的bean
            String[] beanNames = bf.getBeanNamesForAnnotation(HessianService.class);
            for (String bn : beanNames) {
                //构建HessianServiceExporter ，用于发布服务
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(HessianServiceExporter.class);
                String className = bf.getBeanDefinition(bn).getBeanClassName();
                Class<?> clazz = ClassUtils.forName(className, Thread.currentThread().getContextClassLoader());

                //设置ServiceExporter主要两个属性 service,serviceInterface
                //spring 默认的bean名称为类名并首字母小写
                //服务接口的实现已经被spring加载，这时使用addPropertyReference 引用即可
                builder.addPropertyReference("service", toLowerCase(clazz.getSimpleName()));
                builder.addPropertyValue("serviceInterface", clazz.getInterfaces()[0].getName());
                //向容器中注册bean,为Hessian服务设置的bean名称 带有/
                bf.registerBeanDefinition("/" + toLowerCase(clazz.getInterfaces()[0].getSimpleName()), builder.getBeanDefinition());

                log.info("service:" + toLowerCase(clazz.getSimpleName()) + " serviceInterface:" + clazz.getInterfaces()[0].getName());
            }
        } catch (Exception e) {
            log.error("export sever error", e);
        }

    }

    /***
     * 首字母小写
     *
     * @param str
     * @return
     */
    private static String toLowerCase(String str) {
//        char[] chars = new char[1];
//        chars[0] = str.charAt(0);
//        String temp = new String(chars);
//        return str.replaceFirst(temp, temp.toLowerCase());
        return new StringBuilder(str)
                .replace(0, 1, String.valueOf(str.charAt(0)).toLowerCase())
                .toString();
    }

}
